package com.wzw.basics.reflection.generics;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

/**
 * {@link java.lang.reflect.ParameterizedType}
 *
 * 这个接口表示参数化类型，例如List<String>、Map<Integer,String>、UserMapper<UserModel>这种带有泛型的类型。
 *
 * @author Wangzhiwen
 */
public class ParameterizedTypeApi {

    public static void main(String[] args) {
        /*
         * 常用方法
         */
        Class<DemoParams> demoParamsClass = DemoParams.class;
        /*
         * 取泛型类型中的类型列表，就是<>中包含的参数列表，
         * 如：List<String>泛型类型列表只有一个是String，而
         * Map<Integer,String>泛型类型中包含2个类型：Integer和String，
         * UserMapper<UserModel>泛型类型为UserModel，实际上就是<和>中间包含的类型列表。
         */
        Type genericSuperclass = demoParamsClass.getGenericSuperclass();
        ParameterizedType superclass = (ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = superclass.getActualTypeArguments();

        // 返回参数化类型中的原始类型，比如：List<String>的原始类型为List，UserMapper<UserModel>原始类型为UserMapper，也就是<符号前面的部分。
        Type rawType = superclass.getRawType();

        // 返回当前类型所属的类型。例如存在A<T>类，其中定义了内部类InnerA<I>，则InnerA<I>所属的类型为A<I>，如果是顶层类型则返回null。这种关系比较常见的示例是Map<K,V>接口与Map.Entry<K,V>接口，Map<K,V>接口是Map.Entry<K,V>接口的所有者。
        Type ownerType = superclass.getOwnerType();

        TypeVariable<Class<DemoParams>>[] typeParameters = demoParamsClass.getTypeParameters();
        for (TypeVariable<Class<DemoParams>> typeParameter : typeParameters) {
            // 获取泛型变量类型的上边界，如果未明确什么上边界默认为Object。
            // 例如：class Test<K extend Person>中K的上边界只有一个，是Person；
            // 而class Test<T extend List & Iterable>中T的上边界有2个，是List和Iterable
            Type[] bounds = typeParameter.getBounds();

            // 获取声明该泛型变量的原始类型
            // 方法中也可以定义泛型类型的变量，如果在方法中定义，那么上面这个方法返回的就是定义泛型变量的方法了，返回的就是Method对象。
            Class<DemoParams> genericDeclaration = typeParameter.getGenericDeclaration();

            // 获取在源码中定义时的名字，如：class Test<K extend Person>就是K；class Test1<T>中就是T。
            String typeName = typeParameter.getTypeName();
        }
    }

}

class DemoParams extends DemoParamsExt<String, Integer, Long>{

}

class DemoParamsExt<T,K,V> {

}
